﻿namespace SenGe.Domain.Utils
{
    /// <summary>
    /// 编号帮助类
    /// </summary>
    public class IdUtil : IDisposable
    {
        // 常量定义
        private const long Epoch = 1743475780967L; // 自定义纪元时间(2025-04-01 10:49:40 UTC)
        private const int DatacenterIdBits = 5; //5位数据中心编号位【全局最多支持32个数据中心】
        private const int WorkerIdBits = 5; //5位机器编号位【单个数据中心最多支持32个机器】
        private const int SequenceBits = 12; //12位序列号

        private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
        private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);

        private const int WorkerIdShift = SequenceBits;
        private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
        private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;

        private const long SequenceMask = -1L ^ (-1L << SequenceBits);

        // 实例变量
        private long _sequence = 0L;
        private long _lastTimestamp = -1L;

        // 使用 SemaphoreSlim 实现线程安全
        private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

        // 工作节点和数据中心ID
        public long WorkerId { get; }
        public long DatacenterId { get; }

        // 是否已释放
        private bool _disposed = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="workerId"></param>
        /// <param name="datacenterId"></param>
        /// <exception cref="ArgumentException"></exception>
        public IdUtil(long workerId = 5, long datacenterId = 5)
        {
            // 参数校验
            if (workerId > MaxWorkerId || workerId < 0)
                throw new ArgumentException($"Worker ID must be between 0 and {MaxWorkerId}");

            if (datacenterId > MaxDatacenterId || datacenterId < 0)
                throw new ArgumentException($"Datacenter ID must be between 0 and {MaxDatacenterId}");

            WorkerId = workerId;
            DatacenterId = datacenterId;
        }

        public async Task<long> NextIdAsync()
        {
            await _semaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                var timestamp = TimeGen();

                // 时钟回拨处理
                if (timestamp < _lastTimestamp)
                {
                    throw new InvalidOperationException(
                        $"Clock moved backwards. Refusing to generate ID for {_lastTimestamp - timestamp} milliseconds");
                }

                // 同一毫秒内的序列号处理
                if (_lastTimestamp == timestamp)
                {
                    _sequence = (_sequence + 1) & SequenceMask;
                    if (_sequence == 0) // 序列号溢出，等待下一毫秒
                    {
                        timestamp = TilNextMillis(_lastTimestamp);
                    }
                }
                else // 新的一毫秒，重置序列号
                {
                    _sequence = 0L;
                }

                _lastTimestamp = timestamp;

                // 组合各部分生成ID
                return ((timestamp - Epoch) << TimestampLeftShift) |
                       (DatacenterId << DatacenterIdShift) |
                       (WorkerId << WorkerIdShift) |
                       _sequence;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        // 同步版本
        public long NextId()
        {
            _semaphore.Wait();
            try
            {
                var timestamp = TimeGen();
                if (timestamp < _lastTimestamp)
                {
                    throw new InvalidOperationException(
                        $"Clock moved backwards. Refusing to generate ID for {_lastTimestamp - timestamp} milliseconds");
                }
                if (_lastTimestamp == timestamp)
                {
                    _sequence = (_sequence + 1) & SequenceMask;
                    if (_sequence == 0)
                    {
                        timestamp = TilNextMillis(_lastTimestamp);
                    }
                }
                else
                {
                    _sequence = 0L;
                }
                _lastTimestamp = timestamp;
                return ((timestamp - Epoch) << TimestampLeftShift) |
                       (DatacenterId << DatacenterIdShift) |
                       (WorkerId << WorkerIdShift) |
                       _sequence;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        // 等待下一毫秒
        private long TilNextMillis(long lastTimestamp)
        {
            var timestamp = TimeGen();
            while (timestamp <= lastTimestamp)
            {
                timestamp = TimeGen();
            }
            return timestamp;
        }

        // 获取当前时间戳
        private long TimeGen()
        {
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }

        // 实现IDisposable
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _semaphore?.Dispose();
                }
                _disposed = true;
            }
        }

        ~IdUtil()
        {
            Dispose(false);
        }
    }
}
